<script setup lang="ts">
import { onMounted, reactive, ref } from "vue";
import { IconSelect } from "@/components/ReIcon";
import Search from "~icons/ep/search";
import Refresh from "~icons/ep/refresh";
import {
  type wikiCatalogVO,
  addArticle,
  CatalogDTO,
  getCatalog,
  getWikiCatalog,
  removeCatalogById,
  updateCatalog
} from "@/api/blog/wiki";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import EditPen from "~icons/ep/edit-pen";
import Plus from "~icons/ep/plus";
import DocumentRemove from "~icons/ep/document-remove";
import ArrowDownBold from "~icons/ep/arrow-down-bold";
import MoreFilled from "~icons/ic/sharp-more-vert";
import DeleteFilled from "~icons/ep/delete";
import { ElMessage } from "element-plus";
import type { PaginationProps, LoadingConfig } from "@pureadmin/table";
import draggable from "vuedraggable";
import Documents from "~icons/ep/files";
import Document from "~icons/ep/document";
import { updateSortApi, addWikiCatalog } from "@/api/blog/wiki";
import { getArticleList } from "@/api/blog/article";
import { message } from "@/utils/message";
const props = defineProps<{
  wikiId: number | null;
}>();

const form = reactive<CatalogDTO>({
  wikiId: props.wikiId,
  title: "",
  icon: ""
});
const param = reactive({
  currentPage: 1,
  pageSize: 3,
  articleTitle: null
});
const loading = ref(false);
const tableImageList = ref([]);
const tableData = ref([]);
// 分页获取文章
async function pageGetArticleList() {
  loading.value = true;
  const res = await getArticleList(param);

  if (res) {
    tableData.value = res.list;
    pagination.total = res.total;
    tableImageList.value = [];
    tableImageList.value = tableData.value.map(v => {
      return v.cover;
    });
  }
  loading.value = false;
}

const columns: TableColumnList = [
  {
    type: "selection",
    align: "left",
    width: 40
  },
  {
    label: "ID",
    prop: "id",
    width: 55
  },
  {
    label: "标题",
    prop: "articleTitle",
    minWidth: 130
  },
  {
    label: "作者",
    prop: "author",
    minWidth: 60
  },
  {
    label: "是否公开",
    prop: "status",
    minWidth: 80,
    slot: "status"
  },
  {
    label: "封面",
    prop: "cover",
    width: 200,
    slot: "image"
  },
  {
    label: "发布时间",
    prop: "createTime"
  }
];

/** 分页配置 */
const pagination = reactive<PaginationProps>({
  pageSize: 3,
  currentPage: 1,
  pageSizes: [3],
  total: 0,
  align: "right",
  background: true
});
const primaryParam = reactive({ ...param });
// 重置参数
const resetParam = () => {
  Object.assign(param, primaryParam);
  pageGetArticleList();
};

/** 加载动画配置 */
const loadingConfig = reactive<LoadingConfig>({
  text: "正在加载第一页...",
  viewBox: "-10, -10, 50, 50",
  spinner: `
        <path class="path" d="
          M 30 15
          L 28 17
          M 25.61 25.61
          A 15 15, 0, 0, 1, 15 30
          A 15 15, 0, 1, 1, 27.99 7.5
          L 15 15
        " style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
      `
  // svg: "",
  // background: rgba()
});
function onSizeChange(val) {
  param.pageSize = val;
  pageGetArticleList();
}

function onCurrentChange(val) {
  if (typeof val == "number") {
    loadingConfig.text = `正在加载第${val}页...`;
    param.currentPage = val;
    pageGetArticleList();
  }
}
// 选择的文章
const selectList = ref<any>([]);
function handleSelectionChange(val) {
  selectList.value = val;
}

function handleArticleCancel() {
  Object.assign(param, {
    wikiId: props.wikiId,
    title: "",
    icon: ""
  });
  isArticleVisible.value = false;
}
async function handleArticleConfirm() {
  if (selectList.value.length) {
    const articleDTOS = selectList.value.map(item => ({
      id: item.id,
      title: item.articleTitle,
      wikiId: props.wikiId
    }));
    const res = await addArticle(catalogId.value, articleDTOS);
    isArticleVisible.value = false;
    Object.assign(param, {
      wikiId: props.wikiId,
      title: "",
      icon: ""
    });
    if (res) message(res, { type: "success" });
    onSearch();
  } else {
    message("请先选择文章", {
      type: "warning"
    });
  }
}

const catalogList = ref<Array<wikiCatalogVO>>();
const isVisible = ref(false);
const isArticleVisible = ref(false);
const catalogId = ref<number>(undefined);
async function openDialog(id?: number) {
  if (id) {
    const res = await getCatalog(id);
    Object.assign(form, res);
    catalogId.value = id;
  } else {
    catalogId.value = undefined;
    Object.assign(form, {
      title: "",
      icon: ""
    });
  }
  isVisible.value = true;
}

function handleCancel() {
  Object.assign(form, {
    title: "",
    icon: ""
  });
  isVisible.value = false;
}

async function handleConfirm() {
  if (catalogId.value) {
    await updateCatalog(catalogId.value, form);
  } else {
    await addWikiCatalog(form);
  }
  isVisible.value = false;
  onSearch();
}

async function onSearch() {
  const res = await getWikiCatalog(props.wikiId);
  catalogList.value = res;
}

// 一级目录拖拽排序
const onDragEnd = async evt => {
  const { oldIndex, newIndex } = evt;
  if (oldIndex === newIndex) return;

  const source = catalogList.value[oldIndex];
  const target = catalogList.value[newIndex];

  // 交换 sort
  const tempSort = source.sort;
  source.sort = target.sort;
  target.sort = tempSort;

  // 交换位置
  const temp = catalogList.value[oldIndex];
  catalogList.value[oldIndex] = catalogList.value[newIndex];
  catalogList.value[newIndex] = temp;

  // 调用接口更新后端排序
  try {
    await updateSortApi([
      { id: source.id, sort: source.sort },
      { id: target.id, sort: target.sort }
    ]);
    ElMessage.success("一级目录顺序已更新");
  } catch (error) {
    ElMessage.error("更新排序失败");
    // 回滚 UI 交换
    const temp = catalogList.value[oldIndex];
    catalogList.value[oldIndex] = catalogList.value[newIndex];
    catalogList.value[newIndex] = temp;
  }
};

// 子目录拖拽排序
const onChildDragEnd = async (evt, parent) => {
  const { oldIndex, newIndex } = evt;
  if (oldIndex === newIndex || !parent.child) return;

  const source = parent.child[oldIndex];
  const target = parent.child[newIndex];

  // 交换 sort
  const tempSort = source.sort;
  source.sort = target.sort;
  target.sort = tempSort;

  // 交换位置
  const temp = parent.child[oldIndex];
  parent.child[oldIndex] = parent.child[newIndex];
  parent.child[newIndex] = temp;

  try {
    await updateSortApi([
      { id: source.id, sort: source.sort },
      { id: target.id, sort: target.sort }
    ]);
    ElMessage.success("子目录顺序已更新");
  } catch (error) {
    ElMessage.error("更新排序失败");
    // 回滚 UI 交换
    const temp = parent.child[oldIndex];
    parent.child[oldIndex] = parent.child[newIndex];
    parent.child[newIndex] = temp;
  }
};
// 编辑目录
async function editCatalog(id: number) {
  openDialog(id);
}

// 添加文章
async function addArticleCatalog(id: number) {
  catalogId.value = id;
  pageGetArticleList();
  isArticleVisible.value = true;
}
// 移除目录
async function removeCatalog(id: number) {
  try {
    await removeCatalogById(id);
    ElMessage.success("目录已删除");
    isVisible.value = false;
    onSearch();
  } catch (error) {
    ElMessage.error("删除目录失败");
  }
}
// 一级目录: 操作按钮下拉菜单
const handleCommand = command => {
  if (command.action == "edit") {
    // 编辑目录
    editCatalog(command.id);
  } else if (command.action == "addArticle") {
    // 移除出目录
    addArticleCatalog(command.id);
  } else if (command.action == "remove") {
    removeCatalog(command.id);
  }
};
onMounted(() => {
  onSearch();
});
</script>

<template>
  <div>
    <div class="mb-5">
      <el-button type="primary" :icon="Plus" @click="openDialog(undefined)"
        >添加目录</el-button
      >
    </div>

    <div v-if="catalogList?.length">
      <draggable
        :list="null"
        :modelValue="catalogList"
        item-key="id"
        :animation="150"
        handle=".handle"
        @end="onDragEnd"
      >
        <template #item="{ element }">
          <div>
            <!-- 一级目录 -->
            <div class="flex items-center ps-3">
              <div class="pe-2">
                <el-icon color="black" size="12"><ArrowDownBold /></el-icon>
              </div>
              <div class="flex items-center gap-x-2 grow drag-item handle">
                <component
                  :is="
                    useRenderIcon(
                      element.icon && element.icon.length
                        ? element.icon
                        : Documents,
                      { width: 15 }
                    )
                  "
                />
                <span class="flex-grow">{{ element.title }}</span>
              </div>

              <div class="hover:bg-gray-200 rounded py-2 px-1 justify-end">
                <el-dropdown @command="handleCommand">
                  <span class="el-dropdown-link">
                    <component
                      :is="
                        useRenderIcon(MoreFilled, {
                          color: 'black',
                          height: 20,
                          width: 20
                        })
                      "
                    />
                  </span>
                  <template #dropdown>
                    <el-dropdown-menu>
                      <el-dropdown-item
                        :command="{
                          id: element.id,
                          action: 'edit'
                        }"
                      >
                        <el-icon><EditPen /></el-icon>
                        编辑
                      </el-dropdown-item>
                      <el-dropdown-item
                        :command="{
                          id: element.id,
                          action: 'addArticle'
                        }"
                      >
                        <el-icon><Plus /></el-icon>
                        添加文章
                      </el-dropdown-item>
                      <el-dropdown-item
                        :command="{
                          id: element.id,
                          action: 'remove'
                        }"
                      >
                        <el-icon><DocumentRemove /></el-icon>
                        移出目录
                      </el-dropdown-item>
                    </el-dropdown-menu>
                  </template>
                </el-dropdown>
              </div>
            </div>

            <!-- 子目录 -->
            <draggable
              v-if="element.child?.length"
              :list="null"
              :modelValue="element.child"
              item-key="id"
              :animation="150"
              handle=".child-handle"
              @end="evt => onChildDragEnd(evt, element)"
            >
              <template #item="{ element: child }">
                <li
                  class="flex items-center ps-8 py-1 rounded-lg hover:bg-gray-100 child-handle"
                >
                  <div class="flex items-center gap-x-2 grow">
                    <component
                      :is="
                        useRenderIcon(
                          child.icon && child.icon.length
                            ? child.icon
                            : Document,
                          { width: 15 }
                        )
                      "
                    />

                    <span class="flex-grow">{{ child.title }}</span>
                  </div>
                  <span
                    class="hover:bg-gray-200 rounded py-1 px-2"
                    @click="editCatalog(child.id)"
                  >
                    <el-icon><EditPen /></el-icon>
                  </span>
                  <el-tooltip class="box-item" effect="dark" content="移出目录">
                    <span
                      class="hover:bg-gray-200 rounded py-1 px-2"
                      @click="removeCatalog(child.id)"
                    >
                      <el-icon><DeleteFilled color="#666" /></el-icon>
                    </span>
                  </el-tooltip>
                </li>
              </template>
            </draggable>
          </div>
        </template>
      </draggable>
    </div>
    <div v-else>
      <el-empty description="暂无目录" />
    </div>

    <el-dialog
      v-model="isVisible"
      title="添加目录"
      width="400px"
      destroy-on-close
      :draggable="true"
      :closeOnClickModal="false"
      :close-on-press-escape="false"
      :showClose="false"
    >
      <el-form
        :model="form"
        label-width="80px"
        :rules="{
          title: [
            {
              required: true,
              message: '请输入目录名称',
              trigger: ['blur', 'change']
            }
          ]
        }"
      >
        <el-form-item label="名称" prop="title">
          <el-input v-model="form.title" placeholder="请输入目录名称" />
        </el-form-item>
        <el-form-item label="图标">
          <IconSelect v-model="form.icon" class="w-full" />
        </el-form-item>
        <el-form-item>
          <div class="w-full flex justify-end gap-2">
            <el-button type="info" @click="handleCancel">取消</el-button>
            <el-button type="primary" @click="handleConfirm">确认</el-button>
          </div>
        </el-form-item>
      </el-form>
    </el-dialog>
    <el-dialog
      v-model="isArticleVisible"
      class="fixed-dialog"
      title="添加文章"
      width="80%"
      draggable
      :close-on-press-escape="false"
      :close-on-click-modal="false"
    >
      <el-card shadow="never">
        <el-form :inline="true" class="bg-bg_color">
          <el-form-item label="文章标题：">
            <el-input
              v-model="param.articleTitle"
              placeholder="请输入文章标题"
              clearable
            />
          </el-form-item>
          <el-form-item>
            <el-button
              type="primary"
              :icon="useRenderIcon(Search)"
              :loading="loading"
              @click="pageGetArticleList"
            >
              搜索
            </el-button>
            <el-button :icon="useRenderIcon(Refresh)" @click="resetParam">
              重置
            </el-button>
          </el-form-item>
        </el-form>
        <pure-table
          border
          row-key="id"
          alignWhole="center"
          showOverflowTooltip
          :loading="loading"
          :loading-config="loadingConfig"
          :data="tableData"
          :columns="columns"
          :pagination="pagination"
          @size-change="onSizeChange"
          @current-change="onCurrentChange"
          @selection-change="handleSelectionChange"
        >
          <template #image="{ row, index }">
            <el-image
              preview-teleported
              loading="lazy"
              :src="row.cover"
              :preview-src-list="tableImageList.map(v => v)"
              :initial-index="index"
              fit="cover"
              class="w-[160px] h-[80px]"
            />
          </template>
          <template #status="{ row }">
            <el-switch
              v-model="row.status"
              disabled
              :active-value="1"
              :inactive-value="2"
            />
          </template>
        </pure-table>
      </el-card>
      <template #footer>
        <div class="w-full flex justify-end gap-2">
          <el-button type="info" @click="handleArticleCancel">取消</el-button>
          <el-button type="primary" @click="handleArticleConfirm"
            >添加</el-button
          >
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<style scoped lang="scss">
.handle {
  cursor: grab;
}
.child-handle {
  cursor: grab;
}
/* 限制对话框最大高度 */
.fixed-dialog .el-dialog {
  max-height: 80vh;
  display: flex;
  flex-direction: column;
}

/* 设置 body 内容区域滚动 */
.fixed-dialog .el-dialog__body {
  overflow-y: auto;
  flex: 1;
  padding: 20px;
}
</style>
